﻿/**************************************************************
 *
 * 命名空间：Sgr.DataCategories.Domain
 * 创建时间：2025/3/19
 * 描述：行政区划领域模型
 *
 **************************************************************/

using Sgr.Domain.Entities;
using Sgr.Domain.Entities.Auditing;
using Sgr.Exceptions;
using System;

namespace Sgr.DataCategories.Domain.AdministrativeDivisions
{
    /// <summary>
    /// 行政区划
    /// </summary>
    public class AdministrativeDivision : CreationAndModifyAuditedEntity<long, long>, IAggregateRoot, IOptimisticLock, ITreeNode<long>, IHaveCode
    {
        /// <summary>
        /// 无参构造函数，供ORM框架使用
        /// </summary>
        private AdministrativeDivision()
        {
            State = EntityStates.Normal;
        }

        /// <summary>
        /// 创建行政区划
        /// </summary>
        /// <param name="name">名称</param>
        /// <param name="code">代码</param>
        /// <param name="shortName">简称</param>
        /// <param name="pinyinName">拼音名称</param>
        /// <param name="pinyinAbbr">拼音缩写</param>
        /// <param name="description">描述</param>
        internal AdministrativeDivision(
            string name,
            string code,
            string? shortName = null,
            string? pinyinName = null,
            string? pinyinAbbr = null,
            string? description = null)
        {
            ValidateCode(code);
            ValidateName(name);

            ValidataShortName(shortName);
            ValidataPinyinName(pinyinName);
            ValidataPinyinAbbr(pinyinAbbr);

            Name = name;
            Code = code;
            ShortName = shortName;
            PinyinName = pinyinName;
            PinyinAbbr = pinyinAbbr;
            Description = description;
            State = EntityStates.Normal;

            ParentId = 0;

            CalculateLevel();
        }

        #region 属性

        /// <summary>
        /// 行政区划代码
        /// </summary>
        public string Code { get; private set; } = string.Empty;

        /// <summary>
        /// 行政区划名称
        /// </summary>
        public string Name { get; private set; } = string.Empty;

        /// <summary>
        /// 行政区划级别
        /// </summary>
        /// <remarks>0-未知、1-国家，2-省，3-市，4-区县，5-乡镇街道</remarks>
        public int Level { get; private set; }

        /// <summary>
        /// 行政区划简称
        /// </summary>
        public string? ShortName { get; private set; }

        /// <summary>
        /// 拼音名称
        /// </summary>
        public string? PinyinName { get; private set; }

        /// <summary>
        /// 拼音缩写
        /// </summary>
        public string? PinyinAbbr { get; private set; }

        /// <summary>
        /// 行政区划描述
        /// </summary>
        public string? Description { get; private set; }

        /// <summary>
        /// 状态
        /// </summary>
        /// <remarks>Normal-启用，Deactivate-禁用</remarks>
        public EntityStates State { get; private set; }

        /// <summary>
        /// 排序号
        /// </summary>
        public int OrderNumber { get; set; } = 0;

        #endregion 属性

        #region 状态管理

        /// <summary>
        /// 设置行政区划状态
        /// </summary>
        /// <param name="state">实体状态</param>
        public void ChangeEntityState(EntityStates state)
        {
            if (State != state)
            {
                State = state;
                //AddDomainEvent(new AdministrativeDivisionStateChangedDomainEvent(Id, state));
            }
        }

        /// <summary>
        /// 恢复启用
        /// </summary>
        public void Restore()
        {
            if (State == EntityStates.Deactivate)
            {
                State = EntityStates.Normal;
                //AddDomainEvent(new AdministrativeDivisionStateChangedDomainEvent(Id, EntityStates.Normal));
            }
        }

        /// <summary>
        /// 标记删除
        /// </summary>
        public void MarkForDeletion()
        {
            State = EntityStates.Deactivate;
            //AddDomainEvent(new AdministrativeDivisionDeleteDomainEvent(Id));
        }

        #endregion 状态管理

        #region 业务方法

        /// <summary>
        /// 是否为顶级行政区划(国家级)
        /// </summary>
        /// <returns>是否为顶级行政区划</returns>
        public bool IsRoot()
        {
            return ParentId == 0 && Level == 1;
        }

        /// <summary>
        /// 是否为启用状态
        /// </summary>
        /// <returns>是否为启用状态</returns>
        public bool IsActive()
        {
            return State == EntityStates.Normal;
        }

        /// <summary>
        /// 更新基本信息
        /// </summary>
        /// <param name="name">名称</param>
        /// <param name="shortName">简称</param>
        /// <param name="pinyinName">拼音名称</param>
        /// <param name="pinyinAbbr">拼音缩写</param>
        /// <param name="description">描述</param>
        /// <param name="orderNumber">排序号</param>
        public void UpdateBasicInfo(
            string name,
            string? shortName = null,
            string? pinyinName = null,
            string? pinyinAbbr = null,
            string? description = null,
            int? orderNumber = null)
        {
            ValidateName(name);
            ValidataShortName(shortName);
            ValidataPinyinName(pinyinName);
            ValidataPinyinAbbr(pinyinAbbr);

            //string oldName = Name;
            Name = name;
            ShortName = shortName;
            PinyinName = pinyinName;
            PinyinAbbr = pinyinAbbr;
            Description = description;

            if (orderNumber.HasValue)
                OrderNumber = orderNumber.Value;

            //if (oldName != name)
            //    AddDomainEvent(new AdministrativeDivisionNameChangedDomainEvent(Id, name));
        }

        /// <summary>
        /// 修改行政区划代码
        /// </summary>
        /// <param name="code"></param>
        internal void ChangeCode(string code)
        {
            ValidateCode(code);
            if (Code != code)
            {
                Code = code;
                CalculateLevel();
            }
        }

        /// <summary>
        /// 根据行政区划代码自动计算行政区划级别
        /// </summary>
        private void CalculateLevel()
        {
            if (!string.IsNullOrEmpty(Code) && Code.Length == 6)
            {
                Level = Code switch
                {
                    "000000" => 1,
                    _ when Code.EndsWith("0000") => 2,
                    _ when Code.EndsWith("00") => 3,
                    _ => 4,
                };
            }
            else
                Level = 0;
        }

        /// <summary>
        /// 改变父级行政区划
        /// </summary>
        /// <param name="parentId"></param>
        /// <param name="nodePath"></param>
        internal void SetParent(long parentId, string nodePath)
        {
            ValidateNodePath(nodePath);

            this.NodePath = nodePath;

            if (ParentId != parentId)
            {
                //long oldParentId = ParentId;
                this.ParentId = parentId;
                //AddDomainEvent(new AdministrativeDivisionParentChangedDomainEvent(Id, oldParentId, parentId));
            }
        }

        #endregion 业务方法

        #region 验证方法

        /// <summary>
        /// 验证名称
        /// </summary>
        /// <param name="name">名称</param>
        /// <exception cref="ArgumentException">当名称无效时抛出</exception>
        private static void ValidateName(string name)
        {
            if (string.IsNullOrWhiteSpace(name))
                throw DomainException.ValidationError("行政区划名称不能为空");

            if (name.Length > 100)
                throw DomainException.ValidationError("行政区划名称长度不能超过100个字符");
        }

        /// <summary>
        /// 验证代码
        /// </summary>
        /// <param name="code">代码</param>
        /// <exception cref="ArgumentException">当代码无效时抛出</exception>
        private static void ValidateCode(string code)
        {
            if (string.IsNullOrWhiteSpace(code))
                throw DomainException.ValidationError("行政区划代码不能为空");

            if (code.Length > 50)
                throw DomainException.ValidationError("行政区划代码长度不能超过50个字符");
        }

        /// <summary>
        /// 验证节点路径
        /// </summary>
        /// <param name="nodePath"></param>
        /// <exception cref="ArgumentException"></exception>
        private static void ValidateNodePath(string nodePath)
        {
            if (string.IsNullOrEmpty(nodePath))
                throw DomainException.ValidationError("节点路径不能为空");
        }

        private static void ValidataShortName(string? shortName)
        {
            if (!string.IsNullOrEmpty(shortName) && shortName.Length > 50)
                throw DomainException.ValidationError("行政区划简称长度不能超过50个字符");
        }

        private static void ValidataPinyinName(string? pinyinName)
        {
            if (!string.IsNullOrEmpty(pinyinName) && pinyinName.Length > 255)
                throw DomainException.ValidationError("行政区划拼音名称长度不能超过255个字符");
        }

        private static void ValidataPinyinAbbr(string? pinyinAbbr)
        {
            if (!string.IsNullOrEmpty(pinyinAbbr) && pinyinAbbr.Length > 255)
                throw DomainException.ValidationError("行政区划拼音缩写长度不能超过255个字符");
        }

        #endregion 验证方法

        #region ITreeNode (树形结构)

        /// <summary>
        /// 上级行政区划Id
        /// </summary>
        public long ParentId { get; private set; } = 0;

        /// <summary>
        /// 树节点层次目录
        /// </summary>
        public string NodePath { get; private set; } = string.Empty;

        #endregion ITreeNode (树形结构)

        #region IOptimisticLock (乐观锁)

        /// <summary>
        /// 行版本
        /// </summary>
        public long RowVersion { get; set; }

        #endregion IOptimisticLock (乐观锁)
    }
}